import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * Instance.java
 * 
 * The class represents a word on a line in a file. It may or may not be a
 * false positive. Upon instantiation, this class checks if this instance is a
 * false positive and retains the appropriate value.
 * 
 * @author Zachary M. Allen
 */
public class Instance {

	/**
	 * The file from which this instance comes
	 */
	private String file;

	/**
	 * The line on which this instance occurs
	 */
	private int line;

	/**
	 * True if this instance is a false positive, false otherwise
	 */
	private boolean falsePositive;

	/**
	 * Constructor
	 * @param    word    Word that this instance is an instance of
	 * @param    file    File in which this instance occurs
	 * @param    line    Line on which this instance occurs
	 * @param    variableBreakCharacters    The variable break characters used
	 * in constructing the index
	 * @throws    QUIRKException
	 */
	public Instance(String word, String file, int line, String variableBreakCharacters)
			throws QUIRKException {
		
		this.file = file;
		this.line = line;

		BufferedInputStream br = null;
		String lineText = "";
		int lineNumber = 0;
		int nextChar = 0;
		int lastChar = 0;

		try {
			br = new BufferedInputStream(new FileInputStream(file));
		} catch (FileNotFoundException e) {
			throw new QUIRKException(QUIRKException.OUT_OF_DATE_INDEX);
		}

		while ((lineNumber < line) || (nextChar == 13) || (nextChar == 10)) {
			try {
				nextChar = br.read();
			} catch (IOException e) {
				throw new QUIRKException(QUIRKException.OUT_OF_DATE_INDEX);
			}
			if (nextChar == 13 || nextChar == 10) {
				lineNumber++;
				if (nextChar == 10 && lastChar == 13) {
					lineNumber--;
				}
			}
			lastChar = nextChar;
		}

		if (nextChar != 0) {
			lineText += String.valueOf((char) nextChar);
		}

		do {
			try {
				nextChar = br.read();
			} catch (IOException e) {
				throw new QUIRKException(QUIRKException.OUT_OF_DATE_INDEX);
			}
			if (nextChar != 10 && nextChar != 13) {
				lineText += String.valueOf((char) nextChar);
			}
		} while (nextChar != 10 && nextChar != 13 && nextChar != -1);

		lineText = lineText.trim().toLowerCase();
		int index = lineText.indexOf(word);
		
		falsePositive = true;
		nextChar = (char) 0;
		lastChar = (char) 0;
		
		if (index > -1) {
			falsePositive = false;
			if (index > 0) {
				lastChar = lineText.charAt(index - 1);
			}
			if (index + word.length() < lineText.length()) {
				nextChar = lineText.charAt(index + word.length());
			}
			if (!(isBreakChar(nextChar, variableBreakCharacters) && isBreakChar(lastChar, variableBreakCharacters))) {
				falsePositive = true;
			}
		}

	}

	/**
	 * Checks to see if a given character is a break character
	 * @param    nextChar    Character to evaluate
	 * @param    variableBreakCharacters    Variable break characters used to construct index
	 * @return    True if nextChar is a break character, false otherwise
	 */
	private boolean isBreakChar(int nextChar, String variableBreakCharacters) {
		boolean retval = false;
		if (nextChar < 32 || nextChar > 126 || variableBreakCharacters.indexOf(nextChar) > -1) {
			retval = true;
		}
		return retval;
	}

	/**
	 * Determines if two instances are equal
	 * @param    i    The instance to compare to
	 * @return    True if this instance and i are equal, false otherwise
	 */
	public boolean equals(Instance i) {
		boolean retval = false;
		if (file.equals(i.getFile()) && line == i.getLine()) {
			retval = true;
		}
		return retval;
	}

	/**
	 * Getter returns value of falsePositive
	 * @return    Current value of falsePositive
	 */
	public boolean isFalsePositive() {
		return falsePositive;
	}

	/**
	 * Setter sets value of falsePositive
	 * @param    falsePositive    New value of falsePositive
	 */
	public void setFalsePositive(boolean falsePositive) {
		this.falsePositive = falsePositive;
	}

	/**
	 * Getter returns value of file
	 * @return    Current value of file
	 */
	private String getFile() {
		return file;
	}

	/**
	 * Getter returns value of line
	 * @return    Current value of line
	 */
	private int getLine() {
		return line;
	}

	/**
	 * Returns a String representation of this instance in the form 
	 * <code>&ltfile, line&gt</code>
	 * @return    String representation of this instance
	 */
	public String toString() {
		String temp = file;
		while (temp.indexOf(File.separator) > -1) {
			temp = temp.substring(temp.indexOf(File.separator) + 1);
		}
		return "<" + temp + ", " + (line + 1) + ">";
	}

}